#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>

#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

static const int defaultnum = 5;

class ThreadDate {
    public:
        ThreadDate(const std::string &name) :threadname(name) {}
        ~ThreadDate() {}

        std::string getThreadname() { return threadname; };
    private:
        std::string threadname;
};

template <class T>
class ThreadPool {
    public:
        ThreadPool(int thread_num = defaultnum) :_thread_num(thread_num) {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);

            for(int i = 0; i < _thread_num; ++i) {
                std::string threadname = "thread-" + std::to_string(i);
                ThreadDate td(threadname);

                _threads.emplace_back(threadname, std::bind(&ThreadPool<T>::threadRun, this, std::placeholders::_1), td);
                DLOG("%s is created...", threadname.c_str());
            }
        }
        ThreadPool(const ThreadPool<T> &tp) = delete;
        const ThreadPool<T> &operator=(const ThreadPool<T>) = delete;
        ~ThreadPool() {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
    public:
        // 获取单列对象
        // 双重检查锁定
        //不能先上锁，在检查；如果每次获取单例实例时都先上锁，那么无论实例是否已经被创建，所有线程都必须等待锁被释放
        static ThreadPool<T> *getInstance() {
            if(instance == nullptr) {
                LockGuard lockguard(&sig_lock);
                if(instance == nullptr) {
                    DLOG("创建单列成功!!!");
                    instance = new ThreadPool<T>();
                    instance->start();
                }
            }

            return instance;
        }
        // 启动线程池
        bool start() {
            for(auto &thread : _threads) {
                thread.Start();
                DLOG("%s is running!!!", thread.threadname().c_str());
            }

            return true;
        }
        // 线程等待
        void threadWait(ThreadDate &td) {
            DLOG("no task, %s is sleep!!!", td.getThreadname().c_str());
            pthread_cond_wait(&_cond, &_mutex);
        }
        // 线程唤醒
        void threadWakeup() {
            pthread_cond_signal(&_cond);
        }
        // 线程运行
        void threadRun(ThreadDate &td) {
            while(true) {
                T t;
                {
                    LockGuard lockguard(&_mutex);
                    while(_q.empty()) {
                        threadWait(td);
                        DLOG("thread %s is wakeup!!!", td.getThreadname().c_str());
                    }

                    t = _q.front();
                    _q.pop();
                }

                t();
            }
        }
        // 添加任务
        void push(T &in) {
            LockGuard lockguard(&_mutex);
            _q.push(in);
            threadWakeup();
        }
        // 删除线程池
        void wait() {
            for(auto &thread : _threads) 
                thread.Join();
        }
    private:
        std::queue<T> _q; // 任务池
        std::vector<Thread<ThreadDate>> _threads; // 线程池
        int _thread_num; // 线程数量
        pthread_mutex_t _mutex;
        pthread_cond_t _cond; 

        static ThreadPool<T> *instance; // 单列对象
        static pthread_mutex_t sig_lock;
};  

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;